﻿using com.nm.Cache;
using com.nm.Helper;
using com.nm.interfaces;
using com.nm.library.Factorys;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Formatting = Newtonsoft.Json.Formatting;

namespace com.nm
{
    public class SmsSender
    {
        public SubmitResult Send(string mobile, string content)
        {
            var account = "cf_heyue";
            var password = "e115bc404c7749385936f24c523b2016";//密码可以使用明文密码或使用32位MD5加密

            var postStrTpl = "account={0}&password={1}&mobile={2}&content={3}";

            var encoding = new UTF8Encoding();
            var postData = encoding.GetBytes(string.Format(postStrTpl, account, password, mobile, content));

            var myRequest = (HttpWebRequest)WebRequest.Create("http://106.ihuyi.cn/webservice/sms.php?method=Submit");
            myRequest.Method = "POST";
            myRequest.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentLength = postData.Length;

            var newStream = myRequest.GetRequestStream();
            // Send the data.
            newStream.Write(postData, 0, postData.Length);
            newStream.Flush();
            newStream.Close();

            var myResponse = (HttpWebResponse)myRequest.GetResponse();
            if (myResponse.StatusCode == HttpStatusCode.OK)
            {
                var reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
                var res = reader.ReadToEnd();
                var xml = new XmlDocument();
                xml.LoadXml(res);
                var json = JsonConvert.SerializeXmlNode(xml.DocumentElement, Formatting.None, false);
                //Response.Write(json.Substring(16, json.Length - 17));
                Log.WriteLines(res, "SEND SMS", mobile, content);
                var r = JsonConvert.DeserializeObject<SubmitResult>(json.Substring(16, json.Length - 17));
                return r;
            }
            return new SubmitResult()
            {
                code = 0,
                msg = "服务器错误"
            };
        }

        #region Sync版本

        /// <summary>
        /// 发送验证码
        /// </summary>
        /// <param name="mobile"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public Task<SubmitResult> SendCodeSync(string mobile, string code)
        {
            //return SendSync(mobile, "您的验证码是：【" + code + "】。请不要把验证码泄露给其他人。如非本人操作，可不用理会！");
            if (ConfigurationHelper.Get("使用大鱼", false))
            {
                AddDayuTask(mobile, code);
            }
            else
            {
                AddTask(mobile, "您的验证码是：" + code + "。请不要把验证码泄露给其他人。如非本人操作，可不用理会！");
            }

            return Task.FromResult(new SubmitResult());
        }

        /// <summary>
        /// 发送验证码
        /// </summary>
        /// <param name="mobile"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public SubmitResult SendCode(string mobile, string code)
        {
            if (ConfigurationHelper.Get("使用大鱼", false))
            {
                AddDayuTask(mobile, code);
            }
            else
            {
                AddTask(mobile, "您的验证码是：" + code + "。请不要把验证码泄露给其他人。如非本人操作，可不用理会！");
            }
            return new SubmitResult();
        }

        /// <summary>
        /// 异步发送
        /// </summary>
        /// <param name="mobile"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        [Obsolete("请使用AddTask(string Tel, string Msg)")]
        public Task<SubmitResult> SendSync(string mobile, string content)
        {
            var account = "cf_heyue";
            var password = "e115bc404c7749385936f24c523b2016";//密码可以使用明文密码或使用32位MD5加密

            var postStrTpl = "account={0}&password={1}&mobile={2}&content={3}";

            var encoding = new UTF8Encoding();
            var postData = encoding.GetBytes(string.Format(postStrTpl, account, password, mobile, content));

            var myRequest = (HttpWebRequest)WebRequest.Create("http://106.ihuyi.cn/webservice/sms.php?method=Submit");
            myRequest.Method = "POST";
            myRequest.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentLength = postData.Length;

            var newStream = myRequest.GetRequestStream();
            // Send the data.
            newStream.Write(postData, 0, postData.Length);
            newStream.Flush();
            newStream.Close();

            return Task.Run(() =>
            {
                var response = myRequest.GetResponseAsync();
                var myResponse = (HttpWebResponse)response.Result;
                if (myResponse.StatusCode == HttpStatusCode.OK)
                {
                    var reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
                    var res = reader.ReadToEnd();
                    var xml = new XmlDocument();
                    xml.LoadXml(res);
                    var json = JsonConvert.SerializeXmlNode(xml.DocumentElement, Formatting.None, false);
                    //Response.Write(json.Substring(16, json.Length - 17));
                    var r = JsonConvert.DeserializeObject<SubmitResult>(json.Substring(16, json.Length - 17));
                    return r;
                }
                return new SubmitResult()
                {
                    code = 0,
                    msg = "服务器错误"
                };
            });
        }

        /// <summary>
        /// 向多个手机发送相同的信息
        /// </summary>
        /// <param name="mobiles"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        [Obsolete("请使用AddTask(string Tel, string Msg)")]
        public Task<int> SendSync(IEnumerable<string> mobiles, string content)
        {
            var c = 0;
            foreach (var tel in mobiles)
            {
                var r = Send(tel, content);
                System.Threading.Thread.Sleep(1100);
                if (r.code != 0)
                    c++;
            }
            return Task.FromResult(c);
        }

        #endregion Sync版本

        /// <summary>
        /// 添加到队列
        /// </summary>
        /// <param name="Tel"></param>
        /// <param name="Msg"></param>
        public void AddTask(string Tel, string Msg)
        {
            RedisCache.MaxListAdd("send-sms",
                new SmsTaskData
                {
                    Tel = Tel,
                    Msg = Msg
                }.ToJson()
                );
            this.Start();
        }

        /// <summary>
        /// 添加大鱼任务（只支持验证码）
        /// </summary>
        /// <param name="Tel"></param>
        /// <param name="Code"></param>
        public void AddDayuTask(string Tel, string Code)
        {
            RedisCache.MaxListAdd("send-sms",
                new SmsTaskData
                {
                    Tel = Tel,
                    Code = Code,
                    Type = 2,
                }.ToJson()
                );
            this.Start();
        }

        /// <summary>
        /// 添加大鱼任务（只支持验证码）
        /// </summary>
        /// <param name="Tel"></param>
        /// <param name="SmsTemplateCode"></param>
        /// <param name="Values"></param>
        public void AddDayuTask(string Tel, string SmsTemplateCode, IDictionary<string, object> Values)
        {
            RedisCache.MaxListAdd("send-sms",
                new SmsTaskData
                {
                    Tel = Tel,
                    Type = 2,
                    SmsTemplateCode = SmsTemplateCode,
                    Values = Values,
                }.ToJson()
                );
            this.Start();
        }

        protected void Start()
        {
            var factory = FactoryMaker.Get<ITaskFactory>("task-factory", "com.nm.library.Factorys.TaskFactory,com.nm.library");
            factory.Register("check sms sender", 1, (object sender, EventArgs args) =>
            {
                for (var i = 0; i < 10; i++)
                    doSendsms();
            }
        );
            Log.WriteLines("启动任务");
        }

        protected void doSendsms()
        {
            var str = RedisCache.ListPopString("send-sms");
            if (string.IsNullOrWhiteSpace(str))
                return;
            var data = str.FromJson<SmsTaskData>();
            if (data == null)
            {
                Log.WriteLines(str, "解析失败");
                RedisCache.MaxListAdd("send-sms", str);
                return;
            }
            if (data.Times > 9)
            {
                Log.WriteLines(str, "多次发生失败");
                RedisCache.MaxListAdd("send-sms-error", str);
                return;
            }
            if (RedisCache.Exists($"send-sms:{data.Tel}"))
            {
                Log.WriteLines("同一个手机号码一秒钟内不能重复发送");
                RedisCache.MaxListAdd("send-sms", str);
            }
            else
            {
                RedisCache.Add($"send-sms:{data.Tel}", data.Msg, TimeSpan.FromMilliseconds(1010));
                Log.WriteLines("发送。。。", data.Tel, data.Msg);
                var isSuccess = false;
                if (data.Type == 2)
                {
                    var dayu = new DayuSms.SmsSender();
                    var msg = "";
                    if (data.Values?.Count > 0 && !string.IsNullOrWhiteSpace(data.SmsTemplateCode))
                    {
                        isSuccess = dayu.Send(data.SmsTemplateCode, data.Tel, data.Values, out msg);
                    }
                    else
                    {
                        isSuccess = dayu.SendCode(data.Tel, data.Code, out msg);
                    }
                    Log.WriteLines($"发送{data.Tel}结果", msg);
                }
                else
                {
                    var r = Send(data.Tel, data.Msg);
                    isSuccess = r.code == 2;
                    Log.WriteLines($"发送{data.Tel}结果", r.msg);
                }
                if (isSuccess)
                {
                    Log.WriteLines("成功");
                }
                else
                {
                    data.Times++;
                    RedisCache.MaxListAdd("send-sms", data.ToJson());
                }
            }
        }

        /// <summary>
        /// 短信任务
        /// </summary>
        public class SmsTaskData
        {
            /// <summary>
            /// 手机
            /// </summary>
            public string Tel { get; set; }

            /// <summary>
            /// 信息
            /// </summary>
            public string Msg { get; set; }

            /// <summary>
            ///
            /// </summary>
            public string Code { get; set; }

            /// <summary>
            /// 任务类型：2--大鱼
            /// </summary>
            public int Type { get; set; }

            /// <summary>
            /// 发送次数
            /// </summary>
            public int Times { get; set; }

            /// <summary>
            /// 大鱼短信模板
            /// </summary>
            public string SmsTemplateCode { get; set; }

            /// <summary>
            /// 大鱼短信模板变量
            /// </summary>
            public IDictionary<string, object> Values { get; set; }
        }

        /// <summary>
        /// 批量购买会员卡成功发送提醒信息
        /// </summary>
        /// <param name="Tel"></param>
        /// <param name="CardName"></param>
        /// <param name="Num"></param>
        public void SendBatchBuyCard(string Tel, string CardName, int Num)
        {
            var tpl = "您已购买的{0}张{1}会员卡，近期将寄送到您指定的地址，请保持手机畅通，如有疑问请咨询客服电话 4000868321";
            var smsText = string.Format(tpl, Num, CardName);
            AddTask(Tel, smsText);
        }

        /// <summary>
        /// 购买会员卡成功发送提醒信息
        /// </summary>
        /// <param name="Tel"></param>
        /// <param name="CardName"></param>
        /// <param name="Code"></param>
        public void SendBuyCard(string Tel, string CardName, string Code)
        {
            var tpl = "您购买的{0}会员卡，激活码：{1}，激活咨询电话 4000868321";
            var smsText = string.Format(tpl, CardName, Code);
            AddTask(Tel, smsText);
        }

        public class SubmitResult
        {
            public int code { get; set; }
            public string msg { get; set; }
            public int smsid { get; set; }
        }
    }
}